package com.cjl.leetcodeWeeklyMatch;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class fightLord {
    // 当前玩家的牌
    static List<String> ownerPoker =
            List.of("♠3", "♣5", "♦7", "♣9", "♦10", "♣10", "♥10", "♥J", "♦K", "♣2", "♥2", "小王", "大王");

    static String number[] = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
    static String color[] = {"♦", "♣", "♥", "♠"};
    static HashMap<String, Integer> map;

    static {
        // 先对牌进行数额计算
        int serialNumber = 3;
        for (String n : number) {
            for (String c : color) {
                map.put(c + n, serialNumber);
            }
            serialNumber++;
        }
        // 计算大小王额度
        map.put("小王", serialNumber++);
        map.put("大王", serialNumber);
    }

    public static void main(String[] args) {
        /*
         * 写一个斗地主游戏的自动出牌算法，即找出一手牌中跟上家牌型相同且刚好比对方大一点的牌的组合。
         * 重心是自动出牌，不用考虑发牌、其他玩家等因素，要仔细设计自动出牌相关方法。
         * 语言不限，重点考察代码质量和设计能力。网上能搜到的都是不达标的，别被带偏了。
         * （对不了解斗地主规则的人，这里简单介绍下，斗地主的牌型有单牌、对子、三条、五张或以上连张、
         * 三对或以上连对、三带一、三带二、连三、连三带二、炸弹等等）
         * */

    }

    /**
     * 自动出牌方法
     *
     * @param receiveCard 接收到的牌型，根据这个牌型，进行出牌
     * @return 如果有符合条件的牌型可以出则返回，如果没有则返回null
     */
    public static List<String> playPoker(List<String> receiveCard) {
        // 1.先判断当前接收的牌是何类型
        int pokerType = getPokerType(receiveCard);

        // 2.根据牌型进行出牌
        if (pokerType == 1) { // 单牌
            // 获取接收单牌的金额
            Integer pokerNum = map.get(receiveCard.get(0));
            // 获取自己的牌的单张数额进行比较
            for (int i = 0; i < ownerPoker.size(); i++) {
                Integer ownNum = map.get(ownerPoker.get(i));
                if (ownNum > pokerNum) {
                    // 返回当前这张牌
                    String resPoker = ownerPoker.remove(i);
                    return List.of(resPoker);
                }
            }
            // 此时说明没有一张牌匹配则返回null表示过
            return null;
        } else if (pokerType == 2) { // 对子
            // 获取其中一张的数额
            Integer pokerNum = map.get(receiveCard.get(0));
            for (int i = 0; i < ownerPoker.size() - 1; i++) {
                if (ownerPoker.get(i).equals(ownerPoker.get(i + 1))) {
                    Integer ownNum = map.get(ownerPoker.get(i));
                    if (ownNum > pokerNum) {
                        // 找到了与之匹配的连对
                        String p1 = ownerPoker.remove(i);
                        String p2 = ownerPoker.remove(i + 1);
                        return List.of(p1, p2);
                    }
                }
            }
            // 若以上未返回则过
            return null;
        } else if (pokerType == 3) { // 三条
            // 获取其中一张的数额
            Integer pokerNum = map.get(receiveCard.get(0));
            for (int i = 0; i < ownerPoker.size() - 2; i++) {
                // 三张相同才进行判断
                if (ownerPoker.get(i).equals(ownerPoker.get(i + 1)) && ownerPoker.get(i).equals(ownerPoker.get(i + 2))) {
                    Integer ownNum = map.get(ownerPoker.get(i));
                    if (ownNum > pokerNum) {
                        // 找到了与之匹配的三条
                        String p1 = ownerPoker.remove(i);
                        String p2 = ownerPoker.remove(i + 1);
                        String p3 = ownerPoker.remove(i + 2);
                        return List.of(p1, p2, p3);
                    }
                }
            }
            // 若以上未返回则过
            return null;
        } else if (pokerType == 4) { // 炸弹
            // 获取其中一张的数额
            Integer pokerNum = map.get(receiveCard.get(0));
            for (int i = 0; i < ownerPoker.size() - 3; i++) {
                // 三张相同才进行判断
                if (ownerPoker.get(i).equals(ownerPoker.get(i + 1)) && ownerPoker.get(i).equals(ownerPoker.get(i + 2))
                        && ownerPoker.get(i).equals(ownerPoker.get(i + 3))) {
                    Integer ownNum = map.get(ownerPoker.get(i));
                    if (ownNum > pokerNum) {
                        // 找到了与之匹配的炸弹
                        String p1 = ownerPoker.remove(i);
                        String p2 = ownerPoker.remove(i + 1);
                        String p3 = ownerPoker.remove(i + 2);
                        String p4 = ownerPoker.remove(i + 3);
                        return List.of(p1, p2, p3, p4);
                    }
                }
            }
            return null;
        } else if (pokerType == 5) { // 三带一
            // 获取三条其中一个的数额
            Integer pokerNum = map.get(receiveCard.get(1));
            for (int i = 0; i < ownerPoker.size() - 2; i++) {
                // 三张相同才进行判断
                if (ownerPoker.get(i).equals(ownerPoker.get(i + 1)) && ownerPoker.get(i).equals(ownerPoker.get(i + 2))) {
                    Integer ownNum = map.get(ownerPoker.get(i));
                    if (ownNum > pokerNum) {
                        // 找到了与之匹配的三条
                        // 继续找一条
                        for (int j = 0; j < ownerPoker.size(); j++) {
                            if (j != i && j != i + 1 && j != i + 2) {
                                String p1 = ownerPoker.remove(i);
                                String p2 = ownerPoker.remove(i + 1);
                                String p3 = ownerPoker.remove(i + 2);
                                String p4 = ownerPoker.remove(j);
                                return List.of(p1, p2, p3, p4);
                            }
                        }
                    }
                }
            }
            return null;
        } else if (pokerType == 6) {
            // 获取三条其中一个的数额
            Integer pokerNum = map.get(receiveCard.get(2));
            for (int i = 0; i < ownerPoker.size() - 2; i++) {
                // 三张相同才进行判断
                if (ownerPoker.get(i).equals(ownerPoker.get(i + 1)) && ownerPoker.get(i).equals(ownerPoker.get(i + 2))) {
                    Integer ownNum = map.get(ownerPoker.get(i));
                    if (ownNum > pokerNum) {
                        // 找到了与之匹配的三条
                        // 继续找二条
                        for (int j = 0; j < ownerPoker.size() - 1; j++) {
                            // 找到相同的两条并判断是否与上面的三条重合
                            if (ownerPoker.get(j).equals(ownerPoker.get(j + 1))
                                    && (j > i + 2 || j + 1 < i)) {
                                String p1 = ownerPoker.remove(i);
                                String p2 = ownerPoker.remove(i + 1);
                                String p3 = ownerPoker.remove(i + 2);
                                String p4 = ownerPoker.remove(j);
                                String p5 = ownerPoker.remove(j + 1);
                                return List.of(p1, p2, p3, p4, p5);
                            }
                        }
                    }
                }
            }
            return null;
        } else if (pokerType == 7) { // 连三
            // todo 连三和连三带二的比较方法不太了解
        } else if (pokerType == 8) { // 连三带二
            // todo 连三和连三带二的比较方法不太了解
        } else if (pokerType == 9) { // 四带二
            // 获取三条其中一个的数额
            Integer pokerNum = map.get(receiveCard.get(2));
            for (int i = 0; i < ownerPoker.size() - 3; i++) {
                // 三张相同才进行判断
                if (ownerPoker.get(i).equals(ownerPoker.get(i + 1)) && ownerPoker.get(i).equals(ownerPoker.get(i + 2))
                        && ownerPoker.get(i).equals(ownerPoker.get(i + 3))) {
                    Integer ownNum = map.get(ownerPoker.get(i));
                    if (ownNum > pokerNum) {
                        // 找到了与之匹配的四条
                        // 继续找二条
                        for (int j = 0; j < ownerPoker.size() - 1; j++) {
                            // 找到相同的两条并判断是否与上面的三条重合
                            if (ownerPoker.get(j).equals(ownerPoker.get(j + 1))
                                    && (j > i + 3 || j + 1 < i)) {
                                String p1 = ownerPoker.remove(i);
                                String p2 = ownerPoker.remove(i + 1);
                                String p3 = ownerPoker.remove(i + 2);
                                String p4 = ownerPoker.remove(i + 3);
                                String p5 = ownerPoker.remove(j);
                                String p6 = ownerPoker.remove(j + 1);
                                return List.of(p1, p2, p3, p4, p5, p6);
                            }
                        }
                    }
                }
            }
            return null;
        } else if (pokerType == 10) { // 顺子
            // 顺子数量
            int receiveSize = receiveCard.size();
            // 获取顺子第一个的数额
            Integer pokerNum = map.get(receiveCard.get(0));
            for (int i = 0; i < ownerPoker.size(); i++) {
                Integer firstNum = map.get(receiveCard.get(i));
                // 是否找到了顺子
                boolean flag = true;
                // 返回的顺子集合
                ArrayList<String> res = new ArrayList<>();
                if (firstNum > pokerNum && i + receiveSize <= ownerPoker.size()) {
                    // 循环寻找顺子
                    for (int j = i, k = 0; j < ownerPoker.size() && k <= receiveSize; j++, k++) {
                        if (ownerPoker.get(j).equals(ownerPoker.get(j + 1))) {
                            res.add(ownerPoker.get(j));
                        } else {
                            flag = false;
                            res.clear();
                            break;
                        }
                    }
                    // 内循环结束则找到了顺子
                    if (flag) {
                        return res;
                    }
                }
            }
            // 没有符合条件的顺子
            return null;
        } else if (pokerType == 11) { // 连对
            // 连对数量
            int receiveSize = receiveCard.size();
            // 获取连对第一个的数额
            Integer pokerNum = map.get(receiveCard.get(0));
            for (int i = 0; i < ownerPoker.size(); i++) {
                Integer firstNum = map.get(receiveCard.get(i));
                // 是否找到了连对
                boolean flag = true;
                // 返回的顺子集合
                ArrayList<String> res = new ArrayList<>();
                if (firstNum > pokerNum && i + receiveSize <= ownerPoker.size()) {
                    // 循环寻找顺子
                    for (int j = i, k = 0; j < ownerPoker.size() && k <= receiveSize; j += 2, k++) {
                        if (ownerPoker.get(j).equals(ownerPoker.get(j + 1))) {
                            res.add(ownerPoker.get(j));
                            res.add(ownerPoker.get(j + 1));
                        } else {
                            flag = false;
                            res.clear();
                            break;
                        }
                    }
                    // 内循环结束则找到了顺子
                    if (flag) {
                        return res;
                    }
                }
            }
            return null;
        }
        // 此时则一定是王炸,直接过
        return null;
    }

    /**
     * 返回当前接收的的牌的类型
     *
     * @param receiveCard 接收的牌型
     * @return 1-单牌 2-对子 3-三条 4-炸弹 5-三带一 6-三带二 7-连三 8-连三带二 9-四带二 10-顺子 11-连对 0-王炸
     */
    private static int getPokerType(List<String> receiveCard) {
        // 当前接收牌的数量
        int size = receiveCard.size();
        // 先判断顺子和连对
        if (size >= 5) {
            boolean flag1 = true;
            // 判断是否是顺子
            for (int i = 0; i < size - 1; i++) {
                // 如果其中任何一个相邻的元素相等则不是顺子
                if (receiveCard.get(i).equals(receiveCard.get(i + 1))) {
                    flag1 = false;
                    break;
                }
            }
            // 如果是顺子就直接返回
            if (flag1) {
                return 10;
            }

            // 判断是否是连对
            boolean flag2 = true;
            if (size % 2 == 0) {
                int index = 0;
                while (index < size) {
                    // 如果相邻的两个元素不相等则不是连对
                    if (!receiveCard.get(index).equals(receiveCard.get(index + 1))) {
                        flag2 = false;
                        break;
                    }
                    index += 2;
                }
            }
            if (flag2) {
                return 11;
            }
        }

        // 判断其他情况
        switch (size) {
            case 1: // 单牌
                return 1;
            case 2: { // 对子
                // 也有可能是王炸，则需要判断一下
                if (receiveCard.get(0).equals(receiveCard.get(1))) {
                    return 2;
                }
            }
            case 3: // 三条
                return 3;
            case 4: {
                // 数量为4时，可能是炸弹也可能是三带一
                if (receiveCard.get(0).equals(receiveCard.get(3))) {
                    // 炸弹
                    return 4;
                } else {
                    return 5;
                }
            }
            case 5: // 三带二
                return 6;
            case 6: {
                // 数量为6时，可能为连三也可能为四带二
                if (receiveCard.get(0).equals(receiveCard.get(2)) && receiveCard.get(3).equals(receiveCard.get(5))) {
                    return 7;
                } else {
                    return 9;
                }
            }
            default:
                break;
        }
        // 不是以上任意一种情况则是王炸
        return 0;
    }
}
